Source code for hysop.backend.device.opencl.operator.derivative
# Copyright (c) HySoP 2011-2024
#
# This file is part of HySoP software.
# See "https://particle_methods.gricad-pages.univ-grenoble-alpes.fr/hysop-doc/"
# for further info.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sympy as sm
from hysop.symbolic import space_symbols
from hysop.symbolic.complex import ComplexMul
from hysop.constants import DirectionLabels
from hysop.backend.device.opencl.opencl_array_backend import OpenClArrayBackend
from hysop.tools.decorators import debug
from hysop.tools.htypes import check_instance
from hysop.tools.numpywrappers import npw
from hysop.core.memory.memory_request import MemoryRequest
from hysop.backend.device.opencl.opencl_operator import OpenClOperator, op_apply
from hysop.backend.device.opencl.opencl_symbolic import OpenClSymbolic
from hysop.backend.device.opencl.autotunable_kernels.custom_symbolic import (
OpenClAutotunableCustomSymbolicKernel,
)
from hysop.backend.device.opencl.opencl_kernel_launcher import OpenClKernelListLauncher
from hysop.backend.device.opencl.opencl_copy_kernel_launchers import (
OpenClCopyBufferRectLauncher,
)
from hysop.operator.base.derivative import (
FiniteDifferencesSpaceDerivativeBase,
SpectralSpaceDerivativeBase,
)
from hysop.operator.base.custom_symbolic_operator import SymbolicExpressionParser
from hysop.symbolic.relational import Assignment
[docs]
class OpenClFiniteDifferencesSpaceDerivative(
FiniteDifferencesSpaceDerivativeBase, OpenClSymbolic
):
@debug
def __new__(cls, **kwds):
return super().__new__(cls, require_tmp=False, **kwds)
@debug
def __init__(self, **kwds):
super().__init__(require_tmp=False, **kwds)
Fin = self.Fin.s()
Fout = self.Fout.s()
A = self.A
if self.scale_by_field:
A = A.s()
elif self.scale_by_parameter:
if A.size > 1:
raise NotImplementedError
else:
A = A.s
xd = space_symbols[self.direction]
expr = Assignment(Fout, A * Fin.diff(xd, self.directional_derivative))
self.require_symbolic_kernel("compute_derivative", expr)
[docs]
@debug
def setup(self, work):
super().setup(work)
(self.kernel, self.update_parameters) = self.symbolic_kernels[
"compute_derivative"
]
@op_apply
def apply(self, **kwds):
queue = self.cl_env.default_queue
evt = self.kernel(queue=queue, **self.update_parameters())
evt = self.dFout.exchange_ghosts(queue=queue, evt=evt)
[docs]
class OpenClSpectralSpaceDerivative(SpectralSpaceDerivativeBase, OpenClSymbolic):
"""
Compute a derivative of a scalar field in a given direction
using spectral methods.
"""
@debug
def __new__(cls, **kwds):
return super().__new__(cls, **kwds)
@debug
def __init__(self, **kwds):
"""
Initialize a SpectralSpaceDerivative operator on the opencl backend.
See hysop.operator.base.derivative.SpectralSpaceDerivativeBase for
more information.
Parameters
----------
kwds: dict, optional
Base class arguments.
"""
super().__init__(**kwds)
Fs = self.Fin.s()
dFs = self.Fout.s()
Fhs = self.Ft.output_symbolic_array("Fhat")
if self.scale_by_field:
As = A.s()
elif self.scale_by_parameter:
if A.size > 1:
raise NotImplementedError
else:
As = A.s
elif self.scale_by_value:
As = A
else:
As = None
if As is not None:
assert self.scale_by_value or self.scale_by_parameter or self.scale_by_field
expr = Assignment(Fout, As * Fout)
self.require_symbolic_kernel("scale_derivative", expr)
self._do_scale = True
else:
self._do_scale = False
Kr = 1
Kc = None
for wn, indexed_wn in self.tg._indexed_wave_numbers.items():
if wn.is_real:
Kr *= indexed_wn
else:
assert wn.is_complex
if Kc is None:
Kc = indexed_wn
else:
Kc = ComplexMul(Kc, indexed_wn)
if Kc is None:
rhs = Kr * Fhs
else:
rhs = Kr * ComplexMul(Kc, Fhs)
expr = Assignment(Fhs, rhs)
self.require_symbolic_kernel("compute_derivative", expr)
self.Fhs = Fhs
[docs]
@debug
def discretize(self, **kwds):
super().discretize(**kwds)
[docs]
@debug
def setup(self, work):
super().setup(work=work)
if self._do_scale:
(self.scale_kernel, self.scale_update_parameters) = self.symbolic_kernels[
"scale_derivative"
]
else:
self.scale_derivative_kernel = lambda **kwds: None
self.scale_update_parameters = lambda: {}
self.compute_derivative_kernel, _ = self.symbolic_kernels["compute_derivative"]
@op_apply
def apply(self, **kwds):
queue = self.cl_env.default_queue
self.Ft()
self.compute_derivative_kernel(queue=queue)
self.Bt()
self.scale_derivative_kernel(queue=queue, **self.scale_update_parameters())
self.dFout.exchange_ghosts()